import { useEffect, useRef } from 'react';
import { Group, Box3, Mesh, Object3D, Vector3 } from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

interface ModelAttributes {
  name: string;
  realLength: number;
  realWidth: number;
  realHeight: number;
}

interface GLBModelProps {
  url: string;
  dimensions: [number, number, number];
  position?: [number, number, number];
  rotation?: [number, number, number];
  scale?: [number, number, number];
  opacity?: number;
  renderOrder?: number;
  onLoad?: (dimensions: Vector3) => void;
  onCustomAttributesLoad?: (attributes: ModelAttributes) => void;
}

// 创建一个全局 Map 来存储所有模型的原始尺寸
const originalSizesMap = new Map<string, Vector3>();

export function GLBModel({
  url,
  dimensions,
  position = [0, 0, 0],
  rotation = [0, 0, 0],
  opacity = 1,
  renderOrder = 0,
  onLoad,
  onCustomAttributesLoad
}: GLBModelProps) {
  const groupRef = useRef<Group>(null);
  const modelRef = useRef<Object3D | null>(null);

  // 计算并应用缩放
  const calculateAndApplyScale = () => {
    if (!groupRef.current) return;
    const originalSize = originalSizesMap.get(url);
    if (!originalSize) return;

    // 获取目标尺寸
    const [targetLength, targetHeight, targetWidth] = dimensions;

    // 添加一个小的容差值（0.99）来确保模型完全在盒子内部
    const tolerance = 0.99;
    const targetLengthWithTolerance = targetLength * tolerance;
    const targetHeightWithTolerance = targetHeight * tolerance;
    const targetWidthWithTolerance = targetWidth * tolerance;

    // 使用原始尺寸计算缩放比例
    const scaleX = targetLengthWithTolerance / originalSize.x;
    const scaleY = targetHeightWithTolerance / originalSize.y;
    const scaleZ = targetWidthWithTolerance / originalSize.z;

    // 应用缩放
    groupRef.current.scale.set(scaleX, scaleY, scaleZ);
  };

  // 更新位置和旋转
  useEffect(() => {
    if (!groupRef.current) return;
    groupRef.current.position.set(position[0], position[1], position[2]);
    groupRef.current.rotation.set(rotation[0], rotation[1], rotation[2]);
  }, [position, rotation]);

  // 加载模型
  useEffect(() => {
    const loader = new GLTFLoader();
    
    loader.load(url, (gltf) => {
      if (!groupRef.current) return;

      // 移除旧模型
      if (modelRef.current) {
        groupRef.current.remove(modelRef.current);
      }

      const model = gltf.scene;
      modelRef.current = model;
      
      // 计算并保存原始尺寸
      const box = new Box3().setFromObject(model);
      const size = new Vector3();
      box.getSize(size);
      // 获取模型中相机的自定义属性
      let customAttributes: ModelAttributes  = {
        name: '',
        realLength: 0,
        realWidth: 0,
        realHeight: 0,
      };
      for (const child of model.children) {
        if (child.name === 'Camera') {
          customAttributes = child.userData as ModelAttributes;
        }
      }
      // 通知父组件自定义属性
      if (onCustomAttributesLoad) {
        onCustomAttributesLoad(customAttributes as ModelAttributes);
      }
      
      // 保存原始尺寸到 Map 中
      if (!originalSizesMap.has(url)) {
        originalSizesMap.set(url, size.clone());
      }

      // 通知父组件模型尺寸
      if (onLoad) {
        onLoad(size);
      }

      // 应用缩放
      calculateAndApplyScale();

      // 设置材质属性
      model.traverse((child: Object3D) => {
        if (child instanceof Mesh && child.material) {
          child.material.transparent = true;
          child.material.opacity = opacity;
          child.renderOrder = renderOrder;
        }
      });

      // 添加新模型
      groupRef.current.add(model);
    });

    return () => {
      // 清理
      if (modelRef.current && groupRef.current) {
        groupRef.current.remove(modelRef.current);
        modelRef.current = null;
      }
    };
  }, [url]);

  // 监听尺寸、透明度和渲染顺序的变化
  useEffect(() => {
    if (!modelRef.current) return;
    calculateAndApplyScale();
    
    modelRef.current.traverse((child: Object3D) => {
      if (child instanceof Mesh && child.material) {
        child.material.opacity = opacity;
        child.renderOrder = renderOrder;
      }
    });
  }, [dimensions, opacity, renderOrder]);

  return <group ref={groupRef} />;
} 